﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Kokomo.Mirror.CliMetadata
{
	public static class MirrorExtensions
	{
		public static Assembly Mirror(this Assembly assembly, MirrorLoadContext loadContext = null)
		{
			if (loadContext == null) loadContext = MirrorLoadContext.DefaultLoadContext;

			Assembly mirror = loadContext.LoadAssemblyFile(assembly.Location);
			return mirror;
		}
		public static Module Mirror(this Module module, MirrorLoadContext loadContext = null)
		{
			Assembly mirrorAssembly = module.Assembly.Mirror(loadContext);
			Module mirrorModule = mirrorAssembly.GetModule(module.ScopeName);
			return mirrorModule;
		}
		public static TMember Mirror<TMember>(this TMember member, MirrorLoadContext loadContext = null)
			where TMember : MemberInfo
		{
			Module mirrorModule = member.Module.Mirror(loadContext);

			Type[] genericTypeArguments = new Type[0];
			Type[] genericMethodArguments = new Type[0];

			Type type = member as Type;
			if (type != null)
			{
				if (type.IsByRef)
					return (TMember)(MemberInfo)type.GetElementType().Mirror().MakeByRefType();
				else if (type.IsPointer)
					return (TMember)(MemberInfo)type.GetElementType().Mirror().MakePointerType();
				else if (type.IsArray)
					return (TMember)(MemberInfo)type.GetElementType().Mirror().MakeArrayType(type.GetArrayRank());

				genericTypeArguments = type.GetGenericArguments();
			}
			else
			{
				MethodInfo method = member as MethodInfo;
				if (method != null)
				{
					if (method.IsGenericMethod)
						genericMethodArguments = method.GetGenericArguments();
					if (
						(method.DeclaringType != null)
						)
						genericTypeArguments = method.DeclaringType.GetGenericArguments();

				}
			}

			TMember mirrorMember = (TMember)mirrorModule.ResolveMember(member.MetadataToken, genericTypeArguments, genericMethodArguments);
			return mirrorMember;
		}
	}
}
